home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Ham Radio 2000
/
Ham Radio 2000.iso
/
ham2000
/
tcp_ip
/
os2
/
pmnos11s
/
nntpserv.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-07-30
|
56KB
|
2,624 lines
/*
*
* NNTP Server/Client - See RFC977
* Jeffrey R. Comstock. - NR0D - Bloomington, Minnesota USA
* Copyright 1990 Jeffrey R. Comstock, All Rights Reserved.
* Permission granted for non-commercial copying and use, provided
* this notice is retained.
*
* DB3FL 9107xx: heavily rewritten and bug fixing in file-handling
*
* ported to NOS by PE1NMB - 920120
*
* Mods by PA0GRI and WG7J
*/
#include <stdio.h>
#include <time.h>
#include <stdarg.h>
#include <ctype.h>
#include <setjmp.h>
#include <errno.h>
#if !defined(OS2)
#include <dos.h>
#include <dir.h>
#include <io.h>
#endif
#include <sys\stat.h>
#include <string.h>
#include "global.h"
#include "config.h"
#ifdef NNTPS
#include "mbuf.h"
#include "cmdparse.h"
#include "socket.h"
#include "iface.h"
#include "proc.h"
#include "smtp.h"
#include "commands.h"
#include "dirutil.h"
#include "ftp.h"
#include "netuser.h"
#include "nntp.h"
#include "session.h"
#include "files.h"
#include "smtp.h"
#include "bm.h"
#ifdef LESS_WHINING
#include "pc.h"
#include "usock.h"
#include "nr4.h"
#include "netrom.h"
#include "udp.h"
#include "tcp.h"
#include "ip.h"
#endif
int setintrc __ARGS((int16 *var,char *label,int argc, char *argv[],int minval,int16 maxval));
FILE *open_file __ARGS((char *name,char *mode,int s,int t));
FILE *temp_file __ARGS((int s,int t)); /* NMB */
/***************************************************************************/
#undef CONTROL /* reverse NNTP function (not implemented yet) */
#define LINE 80
static int Snntp = -1; /* prototype socket for service */
static int16 Nntpquiet = 0;
int Filecheck = 0; /* flag if file system has been checked */
struct post *Post = NULLPOST;
struct Servers *Nntpserver = NULLSERVER;
static char *Host = NULLCHAR;
static char NEol[] = ".\n";
/*############################ NNTP COMMANDS #################################*/
/* Command table */
static char *commands[] = {
"quit",
#define QUIT_CMD 0
"help",
#define HELP_CMD 1
"list",
#define LIST_CMD 2
"group",
#define GROUP_CMD 3
"debug",
#define DEBUG_CMD 4
"article",
#define ARTICLE_CMD 5
"next",
#define NEXT_CMD 6
"xinfo",
#define XINFO_CMD 7
"ihave",
#define IHAVE_CMD 8
"newnews",
#define NEWNEWS_CMD 9
"head",
#define HEAD_CMD 10
"body",
#define BODY_CMD 11
"stat",
#define STAT_CMD 12
"last",
#define LAST_CMD 13
"slave",
#define SLAVE_CMD 14
NULLCHAR
};
static char artmsg[] = " Article retrieved - ";
static char info[] = "100 %s Info:\n";
static char xinfo[] = "100 No info available\n";
static char debug[] = "100 DEBUG %s\n";
static char nnversion[] = "20%s %s NNTP version %s ready at %s\n";
static char slave[] = "202 SLAVE %s\n";
static char closing[] = "203 Closing\n";
static char listarticle[]= "211 %u %u %u%s\n";
static char retrieve[] = "220 %u%s%shead and body follow\n";
static char head[] = "221 %u%s%sHead\n";
static char body[] = "222 %u%s%sBody\n";
static char statistics[]= "223 %u%s%sStatistics\n";
static char sepcmd[] = "223 %u%s%srequest text separately\n";
static char newnews_t[] = "230 New news by message id follows\n";
static char transok[] = "235 Thanks\n";
static char sendart[] = "335 Send article, end with .\n";
static char nogroup[] = "411 No such newsgroup\n";
static char noselect[] = "412 No newsgroup selected\n";
static char nonext[] = "421 No next article\n";
static char noprev[] = "422 No previous article\n";
static char noart[] = "430 No such article\n";
static char notwanted[] = "435 Article not wanted - do not send it\n";
static char transnotok[]= "437 Article rejected - header garbled - do not try again\n";
static char badsyntax[] = "501 Syntax error\n";
static char error[] = "503 Command not performed\n";
static char nospace[] = "503 Not enough disk space left\n";
static char lowmem[] = "503 System overloaded\n";
static char fatal[] = "503 Fatal error FILE %s\n";
static char quitcmd[] = "QUIT\n";
static char help[] = "NNTP Server 1992,\n\n"
"100 ARTICLE BODY GROUP HEAD HELP IHAVE\n"
"100 LAST LIST NEWNEWS NEXT QUIT STAT\n";
static void
rip2(register char *s)
{
register char *cp;
if((cp = strpbrk(s,"\r\n")) != NULLCHAR)
*cp = '\0';
}
/* main directory-creating routine
* handles special chars in pathname - especially for MSDOS
* returncode: -1 error; 0 success
*/
static int
make_dir(path,s)
char *path;
int s;
{
register char *cp;
if(path == NULLCHAR)
return -1;
#ifdef MSDOS
while((cp = strchr(path,'\\')) != NULLCHAR)
*cp = '/';
#endif
if (access(path,0)) {
if (mkdir(path)) {
tprintf("Can't create %s: %s\n",path,strerror(errno));
if(s)
usprintf(s,fatal,path);
return -1;
}
}
return 0;
}
/* main message-opening routine
* returncode: NULLFILE if error; filepointer success */
static FILE *
open_message(mp,f)
struct nntpsv *mp;
FILE *f;
{
char line[LineLen];
/* mp already checked */
if(f != NULLFILE)
fclose(f);
sprintf(line,"%s/%u",mp->path,mp->pointer);
if ((f = open_file(line,READ_TEXT,0,0)) == NULLFILE)
usputs(mp->s,noart);
return f;
}
/* file-receiving routine
* returncode: -1 if error or 'recvline' faults; 0 success; 1 if blank line */
static int
recv_file(fp,s)
FILE *fp;
int s;
{
char line[LineLen];
int check = 0;
for (;;) {
if (recvline(s,line,LineLen) == -1)
return -1;
rip2(line);
if (strcmp(line,".") == 0) {
return 0;
}
if(!check) { /* only enabled on first line! */
check = 1;
if (*line == '\0') /* check for blank line */
return 1;
}
fprintf(fp,"%s\n",line);
}
}
/* checks incoming article-id against existing articles
* returncode: -1 if error; 1 if article exists; 0 no article found */
static int
check_article(id)
char *id;
{
char *p, line[LineLen];
FILE *f;
if(id == NULLCHAR || (p = strchr(id,'<')) == NULLCHAR
|| (f = open_file(History,READ_TEXT,0,1)) == NULLFILE)
return -1;
for(;;) {
if (fgets(line,LineLen,f) == NULL) {
fclose(f);
return 0;
}
if (strstr(line,p) != NULL) {
fclose(f);
return 1;
}
}
}
/* checks for not valid chars in a line
* returncode: 0 if valid; 1 if invalid */
static int
check_blank(bp)
char *bp;
{
if (strpbrk(bp,"!@#$%^&*()_+=<>,./?~`[]{}\|0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ") == NULL)
return 1;
return 0;
}
/* main file-checking routine
* returncode: -1 if error; 0 success */
static int
check_file(char *path)
{
FILE *hFile;
if(path == NULLCHAR)
return -1;
if(access(path,0)) {
hFile = fopen(path, "W");
if (hFile)
fclose(hFIle);
}
return 0;
}
/* checks if two spaces exists in given string
* returncode: -1 if error; 1 success */
static int
check_one(char *str)
{
register char *cp;
if(str == NULLCHAR || (cp = strchr(str,' ')) == NULLCHAR)
return -1;
cp++;
if (strchr(cp,' ') == NULLCHAR)
return -1;
return 1;
}
/* checks the file-system used for NNTP
* returncode: -1 if error; 0 success - and "Filecheck" is set to 1 */
static int
check_system(void)
{
FILE *f;
char line[LineLen];
int error = 0;
if (Post == NULLPOST)
donnprofile(10,NULL,NULL);
if(Filecheck)
return 0;
error = make_dir(Forward,0);
error |= check_file(Pointer);
error |= check_file(History);
error |= check_file(Active);
error |= check_file(Poll);
if(error)
goto quit;
sprintf(line,"%s/fwd.seq",Newsdir);
if (access(line,0)) {
if((f = open_file(line,"w+",0,1)) == NULLFILE) {
goto quit;
}
fputs("1\n",f);
fclose(f);
}
sprintf(line,"%s/sequence.seq",Mailqdir);
if (access(line,0)) {
if((f = open_file(line,"w+",0,1)) == NULLFILE) {
goto quit;
}
fputs("1\n",f);
fclose(f);
}
Filecheck = 1;
return 0;
quit:
Filecheck = 0;
tputs("Error in NNTP file system\n");
return -1;
}
/* handles the response code of an incoming msg
* returncode: -1 error; 0 no code; value of response code on success */
static int
getreply(cb)
struct nntpsv *cb;
{
int response;
while(recvline(cb->s,cb->buf,LineLen) != -1) {
/* skip informative messages and blank lines */
if(cb->buf[0] == '\0' || cb->buf[0] == '1')
continue;
sscanf(cb->buf,"%d",&response);
return (response < 500) ? response : -1;
}
return -1;
}
/* returncode: -1 error; 1 success; 0 no entry */
static int
get_path(group,mp)
char *group;
struct nntpsv *mp;
{
FILE *f;
char line[LineLen], *cp;
if(group == NULLCHAR || mp == NULLNNTPSV
|| (f = open_file(Pointer,READ_TEXT,mp->s,0)) == NULLFILE)
return -1;
group++;
for (;;) {
if (fgets(line,LineLen,f) == NULL)
break;
if (strcspn(line," ") != strlen(group))
continue;
if (strnicmp(group,line,strlen(group)) == 0) {
cp = (strchr(line,' ')) + 1;
if (mp->path != NULLCHAR)
free(mp->path);
mp->path = strdup(cp);
rip2(mp->path);
fclose(f);
return 1;
}
}
fclose(f);
return 0;
}
/* checkes if path to given article exists
* returncode: -1 error; 1 success; 0 no path */
static int
get_path2(art)
struct article *art;
{
FILE *f;
char line[LineLen], *p;
if(art->group == NULLCHAR
|| (f = open_file(Pointer,READ_TEXT,0,1)) == NULLFILE)
return -1;
p = art->group;
art->path = NULLCHAR;
for (;;) {
if (fgets(line,LineLen,f) == NULL)
break;
if (strcspn(line," ") != strlen(p))
continue;
if (strnicmp(p,line,strlen(p)) == 0) {
p = (strchr(line,' ')) + 1;
if(art->path != NULLCHAR)
free(art->path);
art->path = strdup(p);
rip2(art->path);
fclose(f);
return 1;
}
}
fclose(f);
return 0;
}
/* returncode: -1 if error; 1 success; 0 no pointer */
static int
get_pointer(group,mp)
char *group;
struct nntpsv *mp;
{
FILE *f;
char line[LineLen], *p;
if(group == NULLCHAR || mp == NULLNNTPSV
|| (f = open_file(Active,READ_TEXT,mp->s,0)) == NULLFILE)
return -1;
group++;
for (;;) {
if (fgets(line,LineLen,f) == NULL)
break;
if (strcspn(line," ") != strlen(group))
continue;
if (strnicmp(group,line,strlen(group))==0) {
p = strchr(line,' ');
mp->last = (unsigned)atoi(p);
p++;
mp->first = (unsigned)atoi(strchr(p,' '));
mp->pointer = (mp->first > mp->last ) ? 0 : mp->first;
fclose(f);
return 1;
}
}
fclose(f);
return 0;
}
/* creating path to a new newsgroup
* handling of "." and "\" in pathnames especially MSDOS */
/* returncode: -1 error; 0 success */
static int
make_path(group)
char *group;
{
FILE *f;
char cp[LineLen], cp1[LineLen], *cp2;
int got_it;
if (group == NULLCHAR
|| (f = open_file(Pointer,APPEND_TEXT,0,1)) == NULLFILE)
return -1;
got_it = 0;
strcpy(cp1,group);
for(;;) {
if((cp2 = strchr(cp1,'.')) != NULLCHAR)
*cp2 = '\0';
else
got_it = 1;
sprintf(cp,"%s/%s",Newsdir,cp1);
if(make_dir(cp,0)) {
fclose(f);
return -1;
}
if(got_it) {
fprintf(f,"%s %s\n",group,cp);
fclose(f);
return 0;
}
*cp2 = '/';
}
}
static int
update_list(a)
struct nntpsv *a;
{
FILE *f, *t;
char *p, *p1, l2[LineLen];
if((f = open_file(Active,READ_TEXT,a->s,0)) == NULLFILE)
return -1;
if ((t = temp_file(0,1)) == NULLFILE) {
fclose(f);
return -1;
}
p1 = a->ap->group;
a->ap->number = 0;
for (;;) {
if (fgets(a->buf,LineLen,f) == NULL)
break;
a->ap->tmpu = strcspn(a->buf," ");
strncpy(l2,a->buf,a->ap->tmpu);
l2[a->ap->tmpu] = '\0';
if (strcmp(p1,l2) == 0) {
p = strchr(a->buf,' ') + 1;
a->ap->number = (unsigned)atoi(p);
(a->ap->number)++;
p = strchr(p,' ');
fprintf(t,"%s %5.5u%s",p1,a->ap->number,p);
} else
fputs(a->buf,t);
}
fclose(f);
rewind(t);
if ((f = open_file(Active,WRITE_TEXT,a->s,0)) == NULLFILE) {
fclose(t);
return -1;
}
for(;;) {
if (fgets(a->buf,LineLen,t) == NULL)
break;
fputs(a->buf,f);
}
fclose(t);
if (a->ap->number == 0) {
make_path(a->ap->group);
a->ap->number = 1;
fprintf(f,"%s 00001 00001 y\n",a->ap->group);
}
fclose(f);
return (a->ap->number);
}
/* returncode: -1 error; 0 success */
static int
dup_f(in,out,mp)
FILE *in;
FILE *out;
struct nntpsv *mp;
/* Path: bug in col 1 of article body bug fixed by G4JEC 901019....*/
{
char *p;
int blank_line_flag = 1;
for(;;) {
if (fgets(mp->buf,LineLen,in) == NULL)
return 0;
if (blank_line_flag)
if (strnicmp(mp->buf,Hdrs[PATH],5) == 0) {
p = strchr(mp->buf,' ') + 1;
fprintf(out,"%s%s!%s",Hdrs[PATH],Host,p);
continue;
}
/* oh oh - nntpserv is modifying articles....*/
if (strlen(mp->buf) == 1 && mp->buf[0] == '.')
continue;
fputs(mp->buf,out);
if(!check_blank(mp->buf))
blank_line_flag = 0;
}
}
/* returncode: < 1 if error; 1 success */
static int
dofwd(mp,f,history)
struct nntpsv *mp;
FILE *f;
FILE *history;
{
FILE *fwd;
if(mp == NULLNNTPSV)
return -1;
sprintf(mp->buf,"%s/fwd.seq",Newsdir);
if ((fwd = open_file(mp->buf,"r+",mp->s,0)) == NULLFILE)
return -1;
fgets(mp->buf,LineLen,fwd);
mp->hold_i = atoi(mp->buf) + 1;
fprintf(history," JUNK/%u",mp->hold_i);
rewind(fwd);
fprintf(fwd,"%u",mp->hold_i);
fclose(fwd);
sprintf(mp->buf,"%s/%u",Forward,mp->hold_i);
if ((fwd = open_file(mp->buf,WRITE_TEXT,mp->s,0)) == NULLFILE)
return -2;
rewind(f);
dup_f(f,fwd,mp);
fclose(fwd);
return 1;
}
#ifdef CONTROL
static int
docontrol(f,mp)
FILE *f;
struct nntpsv *mp;
{
struct head *h;
if(f == NULLFILE || mp == NULLNNTPSV
|| (h = (struct head *)callocw(1,sizeof(struct head))) == NULLHEAD))
return -1;
rewind(f);
h->subject = h->from = h->reply_to = h->id = NULLCHAR;
for(;;) {
if ((fgets(mp->buf,LineLen,f)) == NULL)
break;
if (check_blank(mp->buf))
break;
rip2(mp->buf);
if (strncmp(mp->buf,Hdrs[SUBJECT],9) == 0)
h->subject = strdup(mp->buf);
if (strncmp(mp->buf,Hdrs[FROM],6) == 0)
h->from = strdup(mp->buf);
if (strnicmp(mp->buf,Hdrs[REPLYTO],10) == 0)
h->reply_to = strdup(mp->buf);
if (strnicmp(mp->buf,Hdrs[MSGID],12) == 0)
h->id = strdup(strchr(mp->buf,'<'));
}
if (h->subject != NULLCHAR)
if (strncmp(h->subject,"Subject: sendme ",16) == 0)
dosendme(h);
if (h->subject != NULLCHAR)
free(h->subject);
if (h->from != NULLCHAR)
free(h->from);
if (h->reply_to != NULLCHAR)
free(h->reply_to);
if (h->id != NULLCHAR)
free(h->id);
free((char *)h);
return 0;
}
#endif
static int
xfer_article2(f,mp)
FILE *f;
struct nntpsv *mp;
{
char line[LineLen], *p, *group = NULLCHAR, *p1, *from = NULLCHAR;
FILE *fptr, *history;
struct tm *stm;
int x;
#ifdef CONTROL
int control = 0;
#endif
long currtime;
if(f == NULLFILE || mp == NULLNNTPSV ||
(history = open_file(History,APPEND_TEXT,mp->s,0)) == NULLFILE)
return -1;
for (;;) {
if (fgets(line,LineLen,f) == NULL)
break;
rip2(line);
if (strnicmp(line,Hdrs[FROM],6) == 0) {
p = strchr(line,' ') + 1;
from = strdup(p);
continue;
}
if (strnicmp(line,Hdrs[NEWSGROUPS],12) == 0) {
p = strchr(line,' ') + 1;
group = strdup(p);
break;
}
}
time(&currtime);
stm = localtime(&currtime);
fprintf(history,"%s %2.2d%2.2d%2.2d %2.2d%2.2d%2.2d",
mp->id,
stm->tm_year,stm->tm_mon+1,stm->tm_mday,
stm->tm_hour,stm->tm_min,stm->tm_sec);
mp->hold_i = 0;
p = group;
if((mp->ap = (struct article *)callocw(1,sizeof(struct article))) == NULLARTICLE)
goto quit;
x = 1;
while (x) {
if ((p1 = strchr(p,',')) != NULLCHAR) {
p1 = line;
while (*p != ',')
*(p1++)=*(p++);
*p1 = '\0';
p++;
mp->ap->group = strdup(line);
} else {
mp->ap->group = strdup(p);
x = 0;
}
update_list(mp);
if (mp->ap->number > 0) {
get_path2(mp->ap);
mp->hold_i = 1;
sprintf(line,"%s/%u",mp->ap->path,mp->ap->number);
rewind(f);
if ((fptr = open_file(line,WRITE_TEXT,mp->s,0)) == NULLFILE) {
fclose(history);
free(mp->ap->group);
goto quit;
}
dup_f(f,fptr,mp);
fclose(fptr);
fprintf(history," %s/%d",mp->ap->group,mp->ap->number);
#ifdef CONTROL
if (strcmp(mp->ap->group,"control") == 0)
control = 1;
#endif
free(mp->ap->path);
}
free(mp->ap->group);
}
if (mp->hold_i == 0) {
if ((x = dofwd(mp,f,history)) < 1)
mp->hold_i = 0;
}
fputc('\n',history);
fclose(history);
time(&currtime);
if(Nntpquiet < 2)
tprintf("New mail in newsgroup %s\n from <%s> at %s%s",
group,from,ctime(&currtime),
(Nntpquiet < 1) ? "\007" : "");
#ifdef CONTROL
if (control == 1)
docontrol(f,mp);
#endif
quit:
free(from);
free(group);
free((char *)mp->ap);
return 1;
}
static void
nntppoll(unused,cb1,p)
int unused;
void *cb1;
void *p;
{
char *cp, line[LineLen];
struct sockaddr_in fsocket;
struct nntpsv *cb;
struct tm *stm, *ltm;
FILE *f, *f1, *pf;
long t;
int r, now;
struct Servers *sp = (struct Servers *) cb1;
long currtime;
if (!run_timer(&sp->nntpt)) /* if timer had stopped there is an
return; * active session */
if (!Filecheck)
if(check_system())
return;
if(availmem() < Memthresh) {
start_timer(&sp->nntpt);
return;
}
/* check connection window */
time(&currtime);
ltm = localtime(&currtime);
now = ltm->tm_hour * 100 + ltm->tm_min;
if (sp->lowtime < sp->hightime) {
/* doesn't cross midnight */
if (now < sp->lowtime || now >= sp->hightime) {
start_timer(&sp->nntpt);
return;
}
} else {
if (now < sp->lowtime && now >= sp->hightime) {
start_timer(&sp->nntpt);
return;
}
}
if((pf = open_file(Poll,"r+",0,1)) == NULLFILE ||
(cb = (struct nntpsv *)callocw(1,sizeof(struct nntpsv))) == NULLNNTPSV) {
start_timer(&sp->nntpt);
return;
}
stop_timer(&sp->nntpt);
cb->fname = NULLCHAR;
cb->newnews = NULLCHAR;
rewind(pf);
for(t = 0L; fgets(line,LineLen,pf) != NULLCHAR; t = ftell(pf)) {
if((cp = strchr(line,' ')) == NULLCHAR)
continue; /* something wrong with this line, skip it */
*cp = '\0';
if(strnicmp(line,sp->name,strcspn(line," ")-1) == 0) {
rip2(cp+1);
cb->newnews = strdup(cp+1);
/* Prepare to write back the current host and date */
fseek(pf,t,0);
break;
}
}
if(cb->newnews == NULLCHAR)
cb->newnews = strdup("800101 000000");
fsocket.sin_family = AF_INET;
fsocket.sin_addr.s_addr = cb->dest = sp->dest;
fsocket.sin_port = IPPORT_NNTP;
if((cb->s = socket(AF_INET,SOCK_STREAM,0)) == -1)
goto quit;
sockmode(cb->s,SOCK_ASCII);
if(connect(cb->s,(char *)&fsocket,SOCKSIZE) == -1)
goto quit;
log(cb->s,"Connect NNTP");
time(&currtime);
stm = localtime(&currtime);
if(getreply(cb) == -1) /* throw away any hello msg */
goto quit;
#ifdef XXX
usputs(cb->s,"SLAVE\n");
if(getreply(cb) != 202)
goto quit;
#endif
cb->slave = 1;
if ((f = temp_file(0,1)) == NULLFILE)
goto quit;
usprintf(cb->s,"NEWNEWS %s %s\n",sp->newsgroups,cb->newnews);
if(getreply(cb) != 230) {
fclose(f);
goto quit;
}
if(recv_file(f,cb->s) == -1) {
usprintf(cb->s,quitcmd);
fclose(f);
goto quit;
}
if ((f1 = temp_file(cb->s,1)) == NULLFILE) {
fclose(f);
goto quit;
}
rewind(f);
for(;;) {
if (fgets(cb->buf,LineLen,f) == NULL)
break;
rip2(cb->buf);
if (strcmp(cb->buf,".") == 0)
break;
if (check_article(cb->buf) == 1)
continue;
usprintf(cb->s,"ARTICLE %s\n",cb->buf);
for (;;) {
if ((r = recvline(cb->s,cb->buf,LineLen)) == -1)
break;
rip2(cb->buf);
if(!isdigit(cb->buf[0])) {
r = -1;
continue;
} else {
r = atoi(cb->buf);
break;
}
}
if(r == -1)
break;
if (r == 220) {
recv_file(f1,cb->s);
rewind(f1);
for ( ;; ) {
if (fgets(cb->buf,LineLen,f1) == NULL)
break;
rip2(cb->buf);
if (strnicmp(cb->buf,Hdrs[MSGID],12) == 0) {
cb->id = strdup((strchr(cb->buf,' ')) + 1);
break;
}
}
rewind(f1);
xfer_article2(f1,cb);
free(cb->id);
}
fclose(f1);
if ((f1 = temp_file(cb->s,1)) == NULLFILE)
goto quit;
}
fclose(f);
fclose(f1);
usprintf(cb->s,quitcmd);
if (recvline(cb->s,cb->buf,LineLen) == -1)
goto quit;
quit:
if(errno == 0) {
/* Now write back the opening date and time */
fprintf(pf,"%s %02d%02d%02d %02d%02d%02d\n",
sp->name,
stm->tm_year,
stm->tm_mon + 1,
stm->tm_mday,
stm->tm_hour,
stm->tm_min,
stm->tm_sec);
}
fclose(pf);
close_s(cb->s);
free(cb->newnews);
free((char *)cb);
start_timer(&sp->nntpt);
}
static int
ngmatcha(func,dflt,ngspec,matchlist)
int (*func)();
int dflt;
struct g_list *ngspec;
struct g_list *matchlist;
{
register int match;
char *cp;
struct g_list *m,*n;
match = dflt;
m = matchlist;
for(;;) {
if ((cp = strchr(m->str,'/')) != NULLCHAR)
*cp = '\0';
n = ngspec;
for (;;) {
if (n->str[0] == '!') { /* Handle negation */
if ((*func)(n->str+1, m->str)) {
match = 0;
}
} else {
if ((*func)(n->str, m->str)) {
match = 1;
}
}
if (n->next == NULLG)
break;
else
n=n->next;
}
if (m->next == NULLG)
break;
else
m=m->next;
}
return (match);
}
static int
restreql(w, s)
register char *w;
register char *s;
{
while (*s && *w) {
switch (*w) {
case '*':
for (w++; *s; s++)
if (restreql(w, s))
return 1;
break;
default:
if (*w != *s)
return 0;
w++, s++;
break;
}
}
if (*s)
return 0;
while (*w)
if (*w++ != '*')
return 0;
return 1;
}
/* converts timestring to unix-compatible structure
* returncode: 0 (!!) if error; > 0 success */
static int32
make_nntime(d,t,str)
struct date *d;
struct time *t;
char *str;
{
register char *cp;
char tmp[3];
if(str == NULLCHAR)
return 0;
tmp[2] = '\0';
cp = str;
strncpy(tmp,cp,2);
d->tm_year = atoi(tmp)+1900;
if (d->tm_year < 1980)
d->tm_year = 1980;
if (d->tm_year > 2099)
goto quit;
cp+=2;
strncpy(tmp,cp,2);
d->tm_mon = atoi(tmp);
if (d->tm_mon < 1 || d->tm_mon > 12)
goto quit;
cp+=2;
strncpy(tmp,cp,2);
d->tm_day = atoi(tmp);
if (d->tm_day < 1 || d->tm_day > 32)
goto quit;
cp+=3;
strncpy(tmp,cp,2);
t->tm_hour = atoi(tmp);
if (t->tm_hour < 0 || t->tm_hour > 24)
goto quit;
cp+=2;
strncpy(tmp,cp,2);
t->tm_min = atoi(tmp);
if (t->tm_min < 0 || t->tm_min > 60)
goto quit;
cp+=2;
strncpy(tmp,cp,2);
t->tm_sec = atoi(tmp);
if (t->tm_sec < 0 || t->tm_sec > 60)
goto quit;
return (dostounix(d,t));
quit :
return 0L;
}
/* returncode: -1 if error; 0 if no new news; 1 new news available */
static int
newnews(string,mp,f)
char *string;
struct nntpsv *mp;
FILE *f;
{
register int i,j;
char *cp, *cp1, line[LineLen], groups[LineLen];
struct g_list *ng, *hist, *ngp, *histp, *ptr;
FILE *f1;
int all = 1;
if (check_one(string) == -1)
return -1;
cp = string;
i = 1;
while (*(cp++) > 32)
i++;
if (strlen(cp) < 13)
return -1;
strncpy(groups,string,i-1);
groups[i-1] = '\0';
if(strcmp(groups,"*") != 0)
all = 0;
mp->datest = (struct tm *)callocw(1,sizeof(struct tm));
mp->timest = (struct tm *)callocw(1,sizeof(struct tm));
gettime(mp->timest);
getdate(mp->datest);
if ((mp->unixtime = make_nntime(mp->datest,mp->timest,cp)) == 0)
goto quit;
if (mp->unixtime == -1L)
return 0;
if (!all) {
ng = ngp = (struct g_list *)callocw(1,(sizeof(struct g_list)));
cp = groups;
for (;;) {
if ((cp1 = strchr(cp,',')) == NULLCHAR ) {
ng->str = strdup(cp);
ng->next = NULLG;
break;
}
j = strcspn(cp,",");
ng->str = (char *)callocw(1,j+1);
strncpy(ng->str,cp,j);
ng->str[j] = '\0';
ng->next = (struct g_list *)callocw(1,sizeof(struct g_list));
ng = ng->next;
cp1 = strchr(cp,',');
if (cp1 != NULLCHAR)
cp = cp1 + 1;
else
break;
}
}
if ((f1 = open_file(History,READ_TEXT,mp->s,0)) == NULLFILE)
goto quit;
for (;;) {
if (fgets(line,LineLen,f1) == NULL)
break;
rip2(line);
if (!all) {
for(i = 3, cp = line; i; --i)
cp = strchr(cp,' ') + 1;
histp = (struct g_list *)callocw(1,sizeof(struct g_list));
hist = histp;
for (;;) {
if ((cp1 = strchr(cp,' ')) == NULLCHAR) {
hist->str = strdup(cp);
hist->next = NULLG;
break;
}
j = strcspn(cp," ");
hist->str = (char *)callocw(1,j+1);
strncpy(hist->str,cp,j);
hist->str[j] = '\0';
hist->next = (struct g_list *)callocw(1,sizeof(struct g_list));
hist = hist->next;
cp1 = strchr(cp,' ');
if (cp1 != NULLCHAR)
cp = cp1 + 1;
else
break;
}
if (!ngmatcha(restreql,0,ngp,histp)) {
ptr = histp;
for (;;) {
ptr = histp->next;
free(histp->str);
free(histp);
histp = ptr;
if (histp == NULLG)
break;
}
continue;
}
}
cp = strchr(line,' ') + 1;
if ((mp->ftime = make_nntime(mp->datest,mp->timest,cp)) == 0) {
fclose(f1);
goto quit;
}
if ((mp->ftime - mp->unixtime) > 0) {
cp = line;
while ( *cp > 32 )
fputc(*(cp++),f);
fputc('\n',f);
}
if (!all) {
ptr = histp;
for (;;) {
ptr = histp->next;
free(histp->str);
free(histp);
histp = ptr;
if (histp == NULLG)
break;
}
}
}
fclose(f1);
if (!all) {
ptr = ngp;
for (;;) {
ptr = ngp->next;
free(ngp->str);
free(ngp);
ngp = ptr;
if (ngp == NULLG)
break;
}
}
free(mp->datest);
free(mp->timest);
return 1;
quit:
return 0;
}
/* handles incoming newnews-cmd
* returncode: -1 if error; 0 no groups or bad syntax; 1 success */
static int
donewnews(string,mp)
char *string;
struct nntpsv *mp;
{
FILE *f;
int ret;
if((f = temp_file(mp->s,1)) == NULLFILE)
return -1;
ret = newnews(string,mp,f);
switch(ret) {
case -1: /* error in "newnews" routine */
ret = 0;
usputs(mp->s,badsyntax);
break;
case 0: /* no new news */
usputs(mp->s,newnews_t);
usputs(mp->s,NEol);
break;
default: /* new news available, send news file */
rewind(f);
usputs(mp->s,newnews_t);
sendfile(f,mp->s,ASCII_TYPE,0);
usputs(mp->s,NEol);
ret = 1;
break;
}
fclose(f);
return ret;
}
/* change current newsgroup
* returncode: -1 if error; 0 success; 1 no newsgroup */
static int
dogroup(mp,buf)
struct nntpsv *mp;
char *buf;
{
char *p;
int er;
if((p = strchr(buf,' ')) == NULLCHAR)
return -1;
er = get_path(p,mp);
switch (er) {
case 0:
usputs(mp->s,nogroup);
return 1;
default:
p = strchr(buf,' ');
if (get_pointer(p,mp) == 1) {
usprintf(mp->s,listarticle,
mp->last - mp->first + 1,mp->first,mp->last,strchr(buf,' '));
return 0;
}
case -1:
usputs(mp->s,error);
return -1;
}
}
/* checks if newsgroup is selected
* returncode: -1 no group selected; 0 success */
static int
check_grp(mp)
struct nntpsv *mp;
{
if(mp == NULLNNTPSV || mp->path == NULLCHAR) {
usputs(mp->s,noselect);
return -1;
}
return 0;
}
/* get id-number of message
* returncode: -1 if error; 0 if no message; 1 success */
static int
get_id(bp,mp)
char *bp;
struct nntpsv *mp;
{
FILE *f;
char tmp[LineLen];
if ((f = open_message(mp,NULLFILE)) == NULLFILE)
return 0;
for (;;) {
if (fgets(tmp,LineLen,f) == NULL)
break;
if (check_blank(tmp))
break;
if (strnicmp(tmp,Hdrs[MSGID],12)==0) {
fclose(f);
strcpy(bp,strchr(tmp,' '));
rip2(bp);
return 1;
}
}
fclose(f);
strcpy(bp,"\0");
return 0;
}
/* gets next news of newsgroup
* returncode: -1 if error; 0 no news; 1 success */
static int
get_next(mp)
struct nntpsv *mp;
{
FILE *f;
for (;;) {
if (mp->pointer == 0 ) {
usputs(mp->s,nonext);
return 0;
}
if (++(mp->pointer) > mp->last) {
mp->pointer--;
usputs(mp->s,nonext);
return 0;
}
sprintf(mp->buf,"%s/%u",mp->path,mp->pointer);
if ((f = open_file(mp->buf,READ_TEXT,mp->s,0)) != NULLFILE) {
fclose(f);
return 1;
}
}
}
/* gets last news of newsgroup
* returncode: -1 if error; 0 no news; 1 success */
static int
get_last(mp)
struct nntpsv *mp;
{
FILE *f;
for (;;) {
if (mp->pointer == 0) {
usputs(mp->s,noprev);
return 0;
}
if (--(mp->pointer) < mp->first) {
mp->pointer++;
usputs(mp->s,noprev);
return 0;
}
sprintf(mp->buf,"%s/%u",mp->path,mp->pointer);
if ((f = open_file(mp->buf,READ_TEXT,mp->s,0)) != NULLFILE) {
fclose(f);
return 1;
}
}
}
static int
art_ret(mp)
struct nntpsv *mp;
{
if(get_id(mp->buf,mp) == -1)
return -1;
return usprintf(mp->s,retrieve,mp->pointer,mp->buf,artmsg);
}
static int
doarticle(buf,mp) /* Sends article <message-id> to the client */
char *buf;
struct nntpsv *mp;
{
FILE *f;
char *p, *p2, *holds, line[LineLen];
if((p = strchr(buf,'<')) == NULLCHAR
|| (f = open_file(History,READ_TEXT,mp->s,0)) == NULLFILE)
return 0;
for(;;) {
if (fgets(line,LineLen,f) == NULL)
break;
if (strstr(line,p) != NULL) {
fclose(f);
p = (strchr(line,' ')) + 14; /* point to the first newsgroup */
p2 = strchr(p,'/'); /* point to article number */
mp->hold_i = mp->pointer; /* save current pointer */
holds = strdup(mp->path); /* save path of current article */
mp->pointer = atoi((p2 + 1)); /* get the article number */
if (mp->path != NULLCHAR) {
free(mp->path);
mp->path='\0';
}
*p2 = '\0';
rip2(p);
if (strncmp(p+1,"JUNK",6) == 0) {
sprintf(mp->buf,"%s",Forward);
mp->path = strdup(mp->buf);
} else
get_path(p,mp);
if ((f = open_message(mp,f)) == NULLFILE) {
usputs(mp->s,error);
return 0;
}
art_ret(mp);
sendfile(f, mp->s, ASCII_TYPE,0);
fclose(f);
usputs(mp->s,NEol);
free(mp->path);
mp->path=strdup(holds);
mp->pointer=mp->hold_i;
free(holds);
return 1;
}
}
fclose(f);
usputs(mp->s,noart);
return 0;
}
/* checks for a minimum header
* returncode: -1 if error; 0 complete; 1 not complete */
static int
garbled(f)
FILE *f;
{
/*
* The minimum requirement for an incoming article is that it must have
* a newsgroups: line, a message-id: line, and a blank line. This is
* pretty forgiving.
*/
char line[LineLen];
int ok = 0;
rewind(f);
for(;;) {
if (fgets(line,LineLen,f) == NULL)
break;
if (strnicmp(line,Hdrs[NEWSGROUPS],12) == 0)
ok |= 1;
if (strnicmp(line,Hdrs[MSGID],12) == 0)
ok |= 2;
if (ok == 3)
break;
if (check_blank(line))
break;
}
rewind(f);
return (ok == 3) ? 0 : 1;
}
/* returncode: -1 if error; 0 success */
static int
get_article2(mp, id)
struct nntpsv *mp;
char *id;
{
FILE *f;
int ret = -1;
if((f = temp_file(0,1)) == NULLFILE)
return -1;
mp->ap = (struct article *)callocw(1,sizeof(struct article));
mp->id = strdup(id);
usputs(mp->s,sendart);
if(recv_file(f,mp->s) == -1)
goto quit;
if ((ret = garbled(f)) != 0) {
usputs(mp->s,transnotok);
goto quit;
}
if(xfer_article2(f,mp) == 0)
goto quit;
usputs(mp->s,transok);
/* free_ap(mp); <------------ */
quit:
/* free((char *)mp->ap); <------------ */
free(mp->id);
fclose(f);
return ret;
}
void
poll(p)
void *p;
{
newproc("NNTP Client", 2048, nntppoll, 0, p, NULL, 0);
}
static void
nntpserv(s,unused,p)
int s;
void *unused;
void *p;
{
struct nntpsv *mp;
FILE *fp;
long t;
int cnt;
char **cmdp, *arg, *cp, *cmd, buf[LineLen];
sockmode(s,SOCK_ASCII);
sockowner(s,Curproc); /* We own it now */
log(s,"open NNTP");
if (!Filecheck)
if(check_system()) {
usprintf(s,fatal,"STRUCTURE");
log(s,"NNTP error - FILE STRU");
close_s(s);
return;
}
if((mp = (struct nntpsv *)callocw(1,sizeof(struct nntpsv))) == NULLNNTPSV) {
usprintf(s,Nospace);
close_s(s);
return;
}
mp->s = s;
mp->debug = 0;
mp->path = NULLCHAR;
time(&t);
cp = ctime(&t);
cp[24] = '\0';
usprintf(s,nnversion,(Filecheck) ? "0" : "1",Host,Version,cp);
loop:
if ((cnt = recvline(s,buf,LineLen)) == -1) {
/* He closed on us */
goto quit;
}
rip2(buf);
cmd = buf;
/* Translate entire buffer to lower case */
for(cp = cmd; *cp != '\0' ;cp++) {
if ( *cp == ' ' ) break;
*cp = tolower(*cp);
}
/* Find command in table; if not present, return syntax error */
for(cmdp = commands; *cmdp != NULLCHAR; cmdp++)
if(strnicmp(*cmdp,cmd,min(strlen(*cmdp),strlen(cmd))) == 0)
break;
if(*cmdp == NULLCHAR){
usputs(mp->s,badsyntax);
goto loop;
}
arg = &cmd[strlen(*cmdp)];
/* Skip spaces after command */
while(*arg == ' ')
arg++;
/* Execute specific command */
switch(cmdp - commands) {
case QUIT_CMD:
goto quit;
case NEWNEWS_CMD:
if ((cp = strchr(buf,' ')) == NULLCHAR) {
usputs(mp->s,badsyntax);
break;
}
cp++;
donewnews(cp,mp);
break;
case IHAVE_CMD:
if ((cp = strchr(buf,'<')) == NULLCHAR) {
usputs(mp->s,badsyntax);
break;
}
if (check_article(cp) == 1) {
usputs(mp->s,notwanted);
break;
}
if(get_article2(mp,cp))
goto quit;
break;
case HELP_CMD:
usprintf(mp->s,"100 %s - help follows:\n",Host);
if ((fp = open_file(Nhelp,READ_TEXT,0,0)) != NULLFILE ) {
sendfile(fp,mp->s,ASCII_TYPE,0);
fclose(fp);
} else {
usputs(mp->s,help);
}
usputs(mp->s,NEol);
break;
case XINFO_CMD:
if ((fp = open_file(NInfo,READ_TEXT,0,0)) != NULLFILE ) {
usprintf(mp->s,"100 %s - xinfo follows:\n",Host);
sendfile(fp,mp->s,ASCII_TYPE,0);
fclose(fp);
} else {
usputs(mp->s,xinfo);
}
usputs(mp->s,NEol);
break;
case LIST_CMD:
if ((fp = open_file(Active,READ_TEXT,mp->s,0)) != NULLFILE) {
sendfile(fp,mp->s,ASCII_TYPE,0);
fclose(fp);
usputs(mp->s,NEol);
}
break;
case GROUP_CMD :
dogroup(mp,&buf[0]);
break;
case HEAD_CMD : {
if (check_grp(mp))
break;
if (get_id(mp->buf,mp) == 0)
break;
usprintf(mp->s,head,mp->pointer,mp->buf,artmsg);
if ((fp = open_message(mp,fp)) == NULLFILE)
break;
for (;;) {
if ((fgets(mp->buf,LineLen,fp)) == NULL)
break;
if (check_blank(mp->buf))
break;
usprintf(mp->s,"%s",mp->buf);
}
fclose(fp);
usputs(mp->s,NEol);
break;
}
case BODY_CMD : {
if (check_grp(mp))
break;
if (get_id(mp->buf,mp) == 0)
break;
usprintf(mp->s,body,mp->pointer,mp->buf,artmsg);
if ((fp = open_message(mp,fp)) == NULLFILE)
break;
mp->hold_i = 0;
for (;;) {
if ((fgets(mp->buf,LineLen,fp)) == NULL)
break;
if (mp->hold_i)
usputs(mp->s,mp->buf);
if (check_blank(mp->buf))
mp->hold_i = 1;
}
fclose(fp);
usputs(mp->s,NEol);
break;
}
case STAT_CMD : {
if (check_grp(mp))
break;
if (get_id(mp->buf,mp) == 0)
break;
usprintf(mp->s,statistics,mp->pointer,mp->buf,artmsg);
break;
}
case ARTICLE_CMD : {
if (strchr(buf,'<') != NULLCHAR) {
doarticle(buf,mp);
break;
}
if (check_grp(mp))
break;
cp = strchr(buf,'e');
cp++;
if ((cnt < 9 ) || (check_blank(cp))) {
if ((fp = open_message(mp,fp)) == NULLFILE)
break;
art_ret(mp);
sendfile(fp,mp->s,ASCII_TYPE,0);
fclose(fp);
usputs(mp->s,NEol);
break;
}
if ((cp = strpbrk(buf,"0123456789")) != NULLCHAR) {
cnt = atoi(cp);
if ((cnt > mp->last) || ( cnt < mp->first)) {
usputs(mp->s,noart);
break;
}
mp->pointer = cnt;
if ((fp = open_message(mp,fp)) == NULLFILE)
break;
art_ret(mp);
sendfile(fp,mp->s,ASCII_TYPE,0);
fclose(fp);
usputs(mp->s,NEol);
break;
}
break;
}
case NEXT_CMD : {
if (check_grp(mp))
break;
if (get_next(mp) == 1) {
if (get_id(buf,mp) == 1)
usprintf(mp->s,sepcmd,mp->pointer,&buf[1],artmsg);
break;
}
break;
}
case LAST_CMD :
if (check_grp(mp))
break;
if (get_last(mp) == 1 ) {
if (get_id(buf,mp) == 1)
usprintf(mp->s,sepcmd,mp->pointer,&buf[1],artmsg);
break;
}
break;
/* This two following cmds currently are not used for much */
case DEBUG_CMD:
mp->debug = (mp->debug == 0) ? 1 : 0;
usprintf(mp->s,debug,(mp->debug == 0) ? "OFF" : "ON");
break;
case SLAVE_CMD :
mp->slave = (mp->slave == 0) ? 1 : 0;
usprintf(mp->s,slave,(mp->slave == 0) ? "OFF" : "ON");
break;
}
goto loop;
quit:
usputs(mp->s,closing);
log(mp->s,"close NNTP");
close_s(mp->s);
if(mp->path != NULLCHAR)
free(mp->path);
if(mp->newnews != NULLCHAR)
free(mp->newnews);
if(mp->fname != NULLCHAR)
free(mp->fname);
if(mp->id != NULLCHAR);
free(mp->id);
free((char *)mp);
}
/* ---------------------------- NNTP-GATE --------------------------- */
static char * near
mkreplypath(FILE *data)
{
char buf[LINELEN], *cp, *cp1, *path;
sprintf(buf,"%sNNTP_GATE@%s",Hdrs[PATH],Hostname);
path = strdup(buf);
rewind(data);
while((fgets(buf,LINELEN,data)) != 0) {
if(htype(buf) == DATE)
break;
if(htype(buf) == RECEIVED) {
cp = strchr(buf,' ');
cp++;
cp = strchr(cp, ' ');
cp++;
cp1 = strpbrk(cp, ". \0");
*cp1 = '\0';
cp1 = mallocw(strlen(path)+strlen(cp)+2); /* */
sprintf(cp1,"%s!%s",path,cp);
free(path);
path = cp1;
}
}
return(path);
}
int
nnGpost(FILE *data,char *from,struct list *le)
{
struct nntpsv *mp;
char buf[LINELEN], *cp;
FILE *f, *idf;
int32 id;
long currtime;
if (!Filecheck)
if(check_system())
return -1;
if ((f = temp_file(0,1)) == NULLFILE)
return -1;
mp = (struct nntpsv *)callocw(1,sizeof(struct nntpsv));
/* build postuser */
cp = mkreplypath(data);
fprintf(f,"%s\n",cp);
free((char *)cp);
fprintf(f,"%s%s\n",Hdrs[FROM],from);
/*----------------------------------------------------------------*
* build newsgroup *
*-----------------------------------------------------------------*/
if((cp = strchr(le->val,'@')) != NULLCHAR)
*cp = '\0';
fprintf(f,"%s%s\n",Hdrs[NEWSGROUPS],&le->val[1]); /* skip the bang */
/*----------------------------------------------------------------*
* find the subject
*-----------------------------------------------------------------*/
rewind (data);
while((fgets(buf,sizeof(buf),data))!=0) {
if (htype(buf)== SUBJECT)
break;
continue;
}
fputs((*buf == 0) ? "Subject: (none)\n" : buf,f);
/*-------------------------------------------------------------------*
* use msgid of original message
*--------------------------------------------------------------------*/
rewind(data);
while((fgets(buf,sizeof(buf),data))!=0) {
if (htype(buf)== MSGID)
break;
continue;
}
if (*buf == 0) {
sprintf(buf,"%s/sequence.seq",Mailqdir);
idf = open_file(buf,"r+",0,1);
id = atol(fgets(buf,LineLen,idf));
rewind(idf);
fprintf(idf,"%ld",id+2);
fclose(idf);
fprintf(f,"%s<%ld@%s>\n",Hdrs[MSGID],id,Hostname);
sprintf(mp->buf,"<%ld@%s>",id,Hostname);
} else {
fputs(buf,f);
rip(buf);
cp = strchr(buf,'<');
strcpy(mp->buf,cp);
if (check_article(mp->buf))
goto quit;
}
rewind (data);
time(&currtime);
fprintf(f,"Sender: NNTP@%s\n",Hostname);
/*-------------------------------------------------------------------*
* message follows *
*--------------------------------------------------------------------*/
fputs("Comments: Message transferred from SMTP\n",f);
while((fgets(buf,sizeof(buf),data))!=0) {
switch(htype(buf)) {
case FROM:
case MSGID:
case RECEIVED:
fgets(buf,sizeof(buf),data); /*eat the id*/
continue;
}
fputs(buf,f);
}
rewind(f);
mp->id = strdup(mp->buf);
xfer_article2(f,mp);
/*
log(-1,"NNGT: transfer: Msg %s",mp->id);
*/
quit:
fclose(f);
free(mp);
return 0;
}
/* ---------------------------- Servercmd --------------------------- */
/* Start up NNTP receiver service */
int
nntp1(argc,argv,p)
int argc;
char *argv[];
void *p;
{
struct sockaddr_in lsocket;
int s;
if(Snntp != -1)
return -1;
if(check_system() == -1)
return -1;
psignal(Curproc,0); /* Don't keep the parser waiting */
chname(Curproc,"NNTP listener");
lsocket.sin_family = AF_INET;
lsocket.sin_addr.s_addr = INADDR_ANY;
lsocket.sin_port = (argc < 2) ? IPPORT_NNTP : atoi(argv[1]);
Snntp = socket(AF_INET,SOCK_STREAM,0);
bind(Snntp,(char *)&lsocket,sizeof(lsocket));
listen(Snntp,1);
for(;;){
if((s = accept(Snntp,NULLCHAR,(int *)NULL)) == -1)
break; /* Service is shutting down */
/* Low mem check now done in tcpin.c - WG7J */
sockmode(s,SOCK_ASCII);
/* Spawn a server */
newproc("NNTP server",2048,nntpserv,s,NULL,NULL,0);
}
return 0;
}
/* Shutdown NNTP service (existing connections are allowed to finish) */
int
nntp0(argc,argv,p)
int argc;
char *argv[];
void *p;
{
close_s(Snntp);
Snntp = -1;
return 0;
}
/* ---------------------------- Subcmds --------------------------- */
/* lists active newsgroups
* returncode: -1 if error; 0 success */
static int
donnactive(argc,argv,p)
int argc;
char *argv[];
void *p;
{
FILE *fp;
char line[80], *cp;
if((fp = open_file(Active,READ_TEXT,0,1)) == NULLFILE)
return -1;
tputs("Msg# next mod newsgroup\n");
for(;;) {
if (fgets(line,sizeof(line),fp) == NULL)
break;
if((cp = strchr(line,' ')) == NULLCHAR)
break;
*cp = '\0';
rip(++cp);
tprintf("%s %s\n",cp,line);
}
fclose(fp);
return 0;
}
/* add nntp servers to list */
static int
donnadds(argc,argv,p)
int argc;
char *argv[];
void *p;
{
struct Servers *np;
for(np = Nntpserver; np != NULLSERVER; np = np->next)
if(stricmp(np->name,argv[1]) == 0)
break;
if (np == NULLSERVER) {
np = (struct Servers *)callocw(1,sizeof(struct Servers));
if((np->dest = resolve(argv[1])) == 0) {
tprintf(Badhost,argv[1]);
free((char *)np);
return -1;
}
np->name = strdup(argv[1]);
np->next = Nntpserver;
Nntpserver = np;
np->newsgroups = NULLCHAR;
np->lowtime = np->hightime = -1;
np->nntpt.func = poll; /* what to call on timeout */
np->nntpt.arg = (void *)np;
}
if (argc > 3) {
int i;
if (np->newsgroups == NULLCHAR) {
np->newsgroups = callocw(1,LineLen);
*np->newsgroups = '\0';
}
for (i = 3; i < argc; ++i) {
if (isdigit(*argv[i])) {
int lh, ll, hh, hl;
sscanf(argv[i], "%d:%d-%d:%d", &lh, &ll, &hh, &hl);
np->lowtime = lh * 100 + ll;
np->hightime = hh * 100 + hl;
} else if ((strlen(np->newsgroups)+strlen(argv[i])+2) >= LineLen)
tprintf("To many groups, '%s' ignored\n", argv[i]);
else { /* it's a group, and it fits... add it to list */
if (*np->newsgroups != '\0')
strcat(np->newsgroups, ",");
strcat(np->newsgroups, argv[i]);
}
}
if (*np->newsgroups == '\0') { /* No groups specified? */
free(np->newsgroups);
np->newsgroups = NULLCHAR;
}
}
/* set timer duration */
set_timer(&np->nntpt,atol(argv[2])*1000L);
start_timer(&np->nntpt); /* and fire it up */
return 0;
}
/* drops nntp servers from list */
static int
donndrops(argc,argv,p)
int argc;
char *argv[];
void *p;
{
struct Servers *np, *npprev = NULLSERVER;
for(np = Nntpserver; np != NULLSERVER; npprev = np, np = np->next)
if(stricmp(np->name,argv[1]) == 0) {
stop_timer(&np->nntpt);
free(np->name);
if (np->newsgroups)
free(np->newsgroups);
if(npprev != NULLSERVER)
npprev->next = np->next;
else
Nntpserver = np->next;
free((char *)np);
return 0;
}
tputs("No such server enabled.\n");
return -1;
}
/* copies a news from given newsgroup to the mailbox */
static int
donndump(argc,argv,p)
int argc;
char *argv[];
void *p;
{
FILE *t, *f, *o;
char path[LineLen], line[LineLen], *cp, newsname[25], *cp1;
struct ffblk blk;
if (!Filecheck)
if(check_system())
return -1;
if ((f = open_file(Pointer,READ_TEXT,0,1)) == NULLFILE)
return 0;
path[0] = '\0';
line[0] = '\0';
for(;;) {
if (fgets(line,LineLen,f) == NULL)
break;
if (!strncmp(line,argv[1],strlen(argv[1]))) {
cp = strchr(line,' ') + 1;
strcpy(path,cp);
break;
}
}
fclose(f);
if (path[0] == '\0') {
tprintf("No newsgroup %s\n",argv[1]);
goto error;
}
rip2(path);
cp = strrchr(path,'/');
cp1 = &newsname[0];
while(*cp)
*(cp1++) = *(cp++);
*cp1 = '\0';
strcpy(line,path);
strcat(line,"/*.*");
if(findfirst(line,&blk,0)) {
tputs("No news in newsgroup\n");
goto error;
}
if(argc > 2)
sprintf(newsname,"/%s",argv[2]);
sprintf(line,"%s%s.txt",Mailspool,newsname);
if ((o = open_file(line,"a+",0,1)) == NULLFILE)
goto error;
if(!(mlock(Mailspool,newsname))) {
tprintf("Newsgroup dump to %s\n",line);
for (;;) {
if((t = temp_file(0,1)) == NULLFILE) {
fclose(o);
goto error;
}
sprintf(line,"%s/%s",path,blk.ff_name);
/* Open the article */
if ((f = open_file(line,READ_TEXT,0,1)) == NULLFILE) {
fclose(t);
fclose(o);
goto error;
}
pwait(NULL);
tputc('.'); /* One dot/article processed */
tflush();
for (;;) {
if (fgets(line,LineLen,f) == NULL)
break;
fputs(line,t);
if (!strnicmp(line,Hdrs[FROM],6)) {
cp = strchr(line,' ')+1;
fprintf(o,"From %s",cp);
}
}
rewind(t);
for(;;) {
if (fgets(line,LineLen,t) == NULL)
break;
fputs(line,o);
}
fputc('\n',o);
fclose(t);
fclose(f);
if (findnext(&blk))
break;
}
rmlock(Mailspool,newsname);
} else
tputs("Mailfile is busy, try later");
fclose(o);
tputs("\n");
error:
return 0;
}
static int
donnkick(argc,argv,p)
int argc;
char *argv[];
void *p;
{
struct Servers *np;
for(np = Nntpserver; np != NULLSERVER; np = np->next)
if(!stricmp(np->name,argv[1])) {
/* If the timer is not running, the timeout function has
* already been called and we don't want to call it again.
*/
if(run_timer(&np->nntpt) || dur_timer(&np->nntpt) == 0) {
stop_timer(&np->nntpt);
poll((void *)np);
}
return 0;
}
tputs("No server enabled\n");
return 0;
}
/* list nntp servers */
static int
donnlists(argc,argv,p)
int argc;
char *argv[];
void *p;
{
struct Servers *np;
char tbuf[80];
for(np = Nntpserver; np != NULLSERVER; np = np->next) {
if (np->lowtime != -1 && np->hightime != -1)
sprintf(tbuf, " -- %02d:%02d-%02d:%02d",
np->lowtime/100, np->lowtime%100,
np->hightime/100, np->hightime%100);
else
tbuf[0] = '\0';
tprintf("%-32s (%lu/%lu%s)\n Groups: %s\n", np->name,
read_timer(&np->nntpt) /1000L,
dur_timer(&np->nntpt) /1000L,
tbuf, np->newsgroups ? np->newsgroups : "");
}
return 0;
}
/* manually entering new news
* returncode: -1 if error; 0 success */
static int
donnpost(argc,argv,p)
int argc;
char *argv[];
void *p;
{
struct session *sp;
struct nntpsv *mp;
char buf[LineLen];
int id;
FILE *f, *idf, *ufp;
long currtime;
if (!Filecheck)
if(check_system())
return -1;
if((sp = newsession("Post",0,1)) == NULLSESSION)
return -1;
mp = (struct nntpsv *)callocw(1,sizeof(struct nntpsv));
for (;;) {
if ((f = temp_file(0,1)) == NULLFILE)
goto done;
sprintf(buf,"%s/sequence.seq",Mailqdir);
if ((idf = open_file(buf,"r+",0,1)) == NULLFILE) {
tprintf("Please create %s dir ...\n",Mailqdir);
fclose(f);
goto done;
}
id = atoi(fgets(buf,LineLen,idf));
rewind(idf);
fprintf(idf,"%d",id+2);
fclose(idf);
if (Post->user == NULLCHAR) {
tputs("User name? ");
recvline(sp->input,buf,LineLen);
rip2(buf);
Post->user = strdup(buf);
}
fprintf(f,"%s%s\n",Hdrs[PATH],Post->user);
fprintf(f,"%s%s@%s",Hdrs[FROM],Post->user,Hostname);
if (Post->fullname != NULLCHAR)
fprintf(f," (%s )",Post->fullname);
fputc('\n',f);
tputs("Newsgroup? ");
recvline(sp->input,buf,LineLen);
rip2(buf);
if (check_blank(buf))
goto done;
fprintf(f,"%s%s\n",Hdrs[NEWSGROUPS],buf);
tputs("Subject? ");
recvline(sp->input,buf,LineLen);
fprintf(f,"%s%s",Hdrs[SUBJECT],buf);
fprintf(f,"%s<%d@%s>\n",Hdrs[MSGID],id,Hostname);
time(&currtime);
fprintf(f,"Date: %s",ptime(&currtime));
fprintf(f,"Sender: NNTP@%s\n",Hostname);
if (Post->reply != NULLCHAR)
fprintf(f,"%s%s\n",Hdrs[REPLYTO],Post->reply);
if (Post->organ != NULLCHAR)
fprintf(f,"Organization: %s\n",Post->organ);
fputc('\n',f);
tputs("Enter message - end with .\n");
for (;;) {
recvline(sp->input,buf,LineLen);
if(strcmp(buf,".u\n") == 0
|| strcmp(buf,".r\n") == 0) {
tputs("Filename? ");
recvline(sp->input,buf,LineLen);
rip2(buf);
if((ufp = open_file(buf,READ_TEXT,0,1)) != NULLFILE) {
while(fgets(buf,LineLen,ufp) != NULL)
fputs(buf,f);
fclose(ufp);
}
tputs("(continue)\n");
}
if(strcmp(buf,".\n") == 0
|| strcmpi(buf,"***END\n") == 0
|| strcmpi(buf,"/EX\n") == 0)
break;
fputs(buf,f);
}
if (Post->sig != NULLCHAR) {
sprintf(buf,"%s",Post->sig);
if ((idf = open_file(buf,READ_TEXT,0,1)) != NULLFILE ) {
while(fgets(buf,LineLen,idf) != NULL)
fputs(buf,f);
fclose(idf);
}
}
loop: tputs("\n[Send, Abort, Exit, List] ");
recvline(sp->input,buf,LineLen);
switch(tolower(buf[0])) {
case 's':
rewind(f);
sprintf(mp->buf,"<%d@%s>",id,Hostname);
mp->id = strdup(mp->buf);
xfer_article2(f,mp);
break;
case 'l':
rewind(f);
for(;;) {
if (fgets(buf,LineLen,f) == NULL)
break;
tputs(buf);
}
rewind(f);
goto loop;
case 'e':
fclose(f);
goto done;
case 'a':
break;
default:
goto loop;
}
fclose(f);
tputs("Post another? ");
recvline(sp->input,buf,LineLen);
if (tolower(buf[0]) == 'n')
goto done;
}
done:
if(f != NULLFILE)
fclose(f);
keywait(NULLCHAR,1);
free((char *) mp);
freesession(sp);
return 0;
}
static int
donnquiet(argc,argv,p)
int argc;
char *argv[];
void *p;
{
return setintrc(&Nntpquiet,"NNTP quiet",argc,argv,0,2);
}
/* -------------------- Profile subcmds -------------------- */
static int
donnuser(argc,argv,p)
int argc;
char *argv[];
void *p;
{
if(argc < 2 && Post->user != NULLCHAR)
tprintf("%s\n",Post->user);
else {
free(Post->user);
Post->user = strdup(argv[1]);
}
return 0;
}
static int
donnsig(argc,argv,p)
int argc;
char *argv[];
void *p;
{
if(argc < 2 && Post->sig != NULLCHAR)
tprintf("%s\n",Post->sig);
else {
if(access(argv[1],0) == 0) {
free(Post->sig);
Post->sig = strdup(argv[1]);
} else {
tputs("No such signature file\n");
return -1;
}
}
return 0;
}
static int
donnfull(argc,argv,p)
int argc;
char *argv[];
void *p;
{
if(argc < 2 && Post->fullname != NULLCHAR)
tprintf("%s\n",Post->fullname);
else {
free(Post->fullname);
Post->fullname = strdup(argv[1]);
}
return 0;
}
static int
donnhost(argc,argv,p)
int argc;
char *argv[];
void *p;
{
if(argc < 2 && Host != NULLCHAR)
tprintf("%s\n",Host);
else {
free(Host);
Host = strdup(argv[1]);
}
return 0;
}
static int
donnorgan(argc,argv,p)
int argc;
char *argv[];
void *p;
{
if(argc < 2 && Post->organ != NULLCHAR)
tprintf("%s\n",Post->organ);
else {
free(Post->organ);
Post->organ = strdup(argv[1]);
}
return 0;
}
static int
donnreply(argc,argv,p)
int argc;
char *argv[];
void *p;
{
if(argc < 2 && Post->reply != NULLCHAR)
tprintf("%s\n",Post->reply);
else {
free(Post->reply);
Post->reply = strdup(argv[1]);
}
return 0;
}
/* subcmd parser */
static int
donnprofile(argc,argv,p)
int argc;
char *argv[];
void *p;
{
struct cmds Prof[] = {
"fullname", donnfull, 0, 0, NULLCHAR,
"host", donnhost, 0, 0, NULLCHAR,
"organ", donnorgan, 0, 0, NULLCHAR,
"reply", donnreply, 0, 0, NULLCHAR,
"sig", donnsig, 0, 0, NULLCHAR,
"user", donnuser, 0, 0, NULLCHAR,
NULLCHAR,
};
if(Post == NULLPOST) {
Post = (struct post *)callocw(1,sizeof(struct post));
Post->user = Post->reply = Post->sig = Post->organ = Post->fullname = NULLCHAR;
}
if (Host == NULLCHAR) {
Host = strdup(Hostname);
}
return (argc == 10) ? 0 : (subcmd(Prof,argc,argv,p));
}
/* cmd parser */
int
donntp(argc,argv,p)
int argc;
char *argv[];
void *p;
{
struct cmds Nntp[] = {
"active", donnactive, 0, 0, NULLCHAR,
"add", donnadds, 0, 3, "nntp add <nntpserv> <interval> [<groups>]",
"drop", donndrops, 0, 2, "nntp drop <nntpserv>",
"dump", donndump, 0, 2, "nntp dump <newsgroup> [<mailbox>]",
"kick", donnkick, 0, 2, "nntp kick <server>",
"list", donnlists, 0, 0, NULLCHAR,
"post", donnpost, 2024, 0, NULLCHAR,
"profile", donnprofile, 0, 0, NULLCHAR,
"quite", donnquiet, 0, 0, NULLCHAR,
NULLCHAR,
};
return (subcmd(Nntp,argc,argv,p));
}
/* main file-opening routine
* options: s = socketnumber, if given an error msg is printed to the socket
* returncode: NULLFILE if error; filepointer success
*/
FILE *
open_file(name,mode,s,t)
char *name;
char *mode;
int s;
int t;
{
FILE *f;
register char *cp;
if(name == NULLCHAR || mode == NULLCHAR)
return NULLFILE;
#ifdef MSDOS
while((cp = strchr(name,'\\')) != NULLCHAR)
*cp = '/';
#endif
if((f = fopen(name,mode)) == NULLFILE) {
if(s)
usprintf(s,fatal,"",name);
if(t)
tprintf("Can't open %s: %s\n",name,strerror(errno));
}
return f;
}
/* main tempfile-opening routine
* returncode: NULLFILE if error; filepointer success
*/
FILE *
temp_file(s,t)
int s;
int t;
{
FILE *f;
if((f = tmpfile()) == NULLFILE) {
if(s)
usprintf(s,fatal,"TMP","");
if(t) {
tprintf("Can't open TMP: %s\n",strerror(errno));
}
}
return f;
}
/* Subroutine for setting and displaying int variables (with range check) */
int
setintrc(var, label, argc, argv, minval, maxval)
int16 *var;
char *label;
int argc;
char *argv[];
int minval;
int16 maxval;
{
int tmp;
if (argc < 2)
tprintf("%s: %u\n", label, *var);
else {
tmp = atoi(argv[1]);
if (isalpha(*argv[1]) || tmp < minval || tmp > maxval) {
tprintf("%s must be %i..%i\n", label, minval, maxval);
return 1;
}
*var = (int16)tmp;
}
return 0;
}
#endif /* NNTPS */